/**
 * HttpPrintStream is passed to turdlets to handle their output. It is
 * used in the same way as a PrintStream object would be used, and sort
 * of like what you have in php. Any calls to the various <code>print</code>
 * /<code>println</code>, etc. methods below will cause the header to be
 * sent and closed automatically before the data is sent. In order to
 * manipulate the headers which will be sent, there are the 
 * <code>setStatus</code>, <code>setContentType</code>, and <code>header</code>
 * methods, which must be called prior to writing any data to the stream.
 * Attempts to write headers to a stream which has already sent data will
 * be silently ignored.
 *
 * @author micha
 *
 */

package tomkitty.server;

import tomkitty.turdlet.*;
import tomkitty.util.*;
import java.io.PrintStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.String;

public class HttpPrintStream implements HttpConstants {

	static final byte[] EOL = {(byte)'\r', (byte)'\n' };

	private String status = HTTP_OK;
	private String contentType = "text/html";
	private PrintStream ps;
	private boolean headerStarted = false;
	private boolean headerFinished = false;
	private boolean headersOnly = false;

	/**
	 *
	 * Set whether to send only headers. This is used for the HEAD method,
	 * for example. Calls to any of the <code>print</code>, etc. methods
	 * will be ignored, and only headers sent if enabled. This is disabled
	 * by default.
	 *
	 * @param b <i>true</i> to enable, <i>false</i> to disable (default)
	 */
	public void sendHeadersOnly(boolean b) {
		headersOnly = b;
	}

	public HttpPrintStream(OutputStream out) {
		ps = new PrintStream(out);
	}

	public HttpPrintStream(OutputStream out, boolean autoflush) {
		ps = new PrintStream(out, autoflush);
	}

	public HttpPrintStream(OutputStream out, boolean autoflush, String encoding) 
	throws UnsupportedEncodingException {
		ps = new PrintStream(out, autoflush, encoding);
	}

	/**
	 *
	 * Get the HTTP status string, like <i>200 OK</i> for example.
	 */
	public String getStatus(String status) {
		return status;
	}

	/**
	 *
	 * Set the HTTP status code.
	 *
	 * @param status HTTP status code string.
	 * @see HttpConstants
	 */
	public void setStatus(String status) {
		this.status = status;
	}

	/**
	 *
	 * Get the response content type.
	 */
	public String getContentType(String contentType) {
		return contentType;
	}

	/**
	 *
	 * Set the response content type header field. The default is 
	 * <i>text/html</i>.
	 *
	 * @param contentType response content type string
	 */
	public void setContentType(String contentType) {
		this.contentType = contentType;
	}

	private void header() {
		try {
			if (! headerStarted) {
				ps.print("HTTP/1.0 " + status);
				ps.write(EOL);
				ps.print("Content-type: " + contentType);
				ps.write(EOL);
				headerStarted = true;
			}
		} catch (IOException ioe) {
				
		}
	}

	private void endHeader() {
		try {
			if (! headerStarted) {
				header();
			}
			if (!headerFinished) {
				ps.write(EOL);
				ps.write(EOL);
				headerFinished = true;
			}
		} catch (IOException ioe) {
				
		}
	}

	/**
	 *
	 * Append additional line to the HTTP response header. This causes the
	 * status line to be sent, as well, so the <code>setStatus</code> and
	 * <code>setContentType</code> methods will have no effect after this
	 * method is called.
	 *
	 * @param headerLine the additional line
	 */
	public void header(String headerLine) {
		try {
			if (! headerStarted) {
				header();
			}
			ps.print(headerLine);
			ps.write(EOL);
		} catch (IOException ioe) {
				
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void print(boolean b) {
		endHeader();
		if (! headersOnly) {
			ps.print(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void print(char b) {
		endHeader();
		if (! headersOnly) {
			ps.print(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void print(char[] b) {
		endHeader();
		if (! headersOnly) {
			ps.print(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void print(double b) {
		endHeader();
		if (! headersOnly) {
			ps.print(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void print(float b) {
		endHeader();
		if (! headersOnly) {
			ps.print(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void print(int b) {
		endHeader();
		if (! headersOnly) {
			ps.print(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void print(long b) {
		endHeader();
		if (! headersOnly) {
			ps.print(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void print(Object b) {
		endHeader();
		if (! headersOnly) {
			ps.print(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void print(String b) {
		endHeader();
		if (! headersOnly) {
			ps.print(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 */
	public void println() {
		endHeader();
		if (! headersOnly) {
			ps.println();
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void println(boolean b) {
		endHeader();
		if (! headersOnly) {
			ps.println(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void println(char b) {
		endHeader();
		if (! headersOnly) {
			ps.println(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void println(char[] b) {
		endHeader();
		if (! headersOnly) {
			ps.println(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void println(double b) {
		endHeader();
		if (! headersOnly) {
			ps.println(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void println(float b) {
		endHeader();
		if (! headersOnly) {
			ps.println(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void println(int b) {
		endHeader();
		if (! headersOnly) {
			ps.println(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void println(long b) {
		endHeader();
		if (! headersOnly) {
			ps.println(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void println(Object b) {
		endHeader();
		if (! headersOnly) {
			ps.println(b);
		}
	}

	/**
	 *
	 * Prints stuff to the stream. This causes the header to be sent, if
	 * necessary, before and data is printed, so subsequent calls to the
	 * <code>setStatus</code>, <code>setContentType</code>, or
	 * <code>header</code> methods will have no effect.
	 *
	 * @param b stuff to print
	 */
	public void println(String b) {
		endHeader();
		if (! headersOnly) {
			ps.println(b);
		}
	}

}
